package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.search.vos.SearchArticleRetVo;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.search.service.ArticleSearchService;
import com.heima.search.service.UserSearchHistoryService;
import com.heima.utils.thread.WmThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Autowired
    UserSearchHistoryService historyService;


    @Override
    public ResponseResult search(UserSearchDto dto) {
        log.info("线程名  {}  搜索  参数 {}", Thread.currentThread().getName(),  dto);
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getPageNum()<1) dto.setPageNum(1);//实际分页是按getMinBehotTime时间处理的   pageNum不需要了
        if(dto.getPageSize()<1 || dto.getPageSize()>100) dto.setPageSize(10);


        //如果用户登陆了  且第一次搜索该关键字则执行保存动作
        WmUser user = WmThreadLocalUtil.getUser();
        if(user!=null && StringUtils.isNotBlank(dto.getSearchWords()) && dto.getFromIndex()==0){
            historyService.insert(dto, user.getId());//开启新线程保存搜索记录
        }





        //2.构建搜索请求对象 SearchRequest对象
        SearchRequest searchRequest = new SearchRequest("app_info_article_111");//索引库名称

        //3.构建dsl条件
        SearchSourceBuilder ssb = new SearchSourceBuilder();//搜索条件对象
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();//组合条件

        //关键字    用搜索   会计算得分
        if(StringUtils.isNotBlank(dto.getSearchWords())){
            QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords())
                    .field("title", 10)
                    .field("content")
                    .defaultOperator(Operator.OR);
            boolQueryBuilder.must(queryStringQueryBuilder);//必须满足
        }



        if(dto.getMinBehotTime()!=null){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
            //时间    用过滤   不计算的分   性能比较高
            boolQueryBuilder.filter(rangeQueryBuilder);
        }

        //分页处理
        ssb.from(0);
        ssb.size(dto.getPageSize());

        //按发布时间降序
        ssb.sort("publishTime", SortOrder.DESC);

        ssb.query(boolQueryBuilder);

        //高亮处理  三要素  高亮字段  前缀    后缀
        HighlightBuilder highligterBuild = new HighlightBuilder();
        highligterBuild.field("title");
        highligterBuild.preTags("<font style='color: red; font-size: inherit;'>");
        highligterBuild.postTags("</font>");
        highligterBuild.requireFieldMatch(false);//如果搜索的字段和高亮字段不一致  需要设置该项
        ssb.highlighter(highligterBuild);

        searchRequest.source(ssb);

        //4.发起请求
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //5.解析es的响应
            List<SearchArticleVo> list = new ArrayList<>();
            SearchHits searchHits = response.getHits();
            long value = searchHits.getTotalHits().value;//总记录数
            SearchHit[] hits = searchHits.getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                SearchArticleRetVo vo = JSON.parseObject(sourceAsString, SearchArticleRetVo.class);


            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightField = highlightFields.get("title");//有可能为null
                if(highlightField!=null){
                    Text[] fragments = highlightField.getFragments();
                    if(fragments!=null && fragments.length>0){
                        String highlightTitle = StringUtils.join(fragments);
                        if(StringUtils.isNotBlank(highlightTitle)){
                            vo.setH_title(highlightTitle);//将高亮的结果  赋值给h_title
                        }else{
                            vo.setH_title(vo.getTitle());//将title字段值  拷贝导h_title字段   因为前端用的h_title
                        }
                    }
                }else{
                    vo.setH_title(vo.getTitle());//将title字段值  拷贝导h_title字段   因为前端用的h_title
                }
                list.add(vo);
            }

            //6.封装结果并返回
            return ResponseResult.okResult(list);


        } catch (IOException e) {
            e.printStackTrace();
            log.error("搜索es保存了",e);
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }
}
